package com.harry.configuration.web.interceptor.outest;

import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.harry.configuration.ConstSettings;
import com.harry.decoupling.defi.proxy.GenericSrvProxy;
import com.harry.resource.inner.entity.InnerUser;
import com.harry.utility.BeanCtxUtils;
import com.harry.utility.InnerUtils;
import com.harry.utility.JwtUtils;
import com.harry.utility.PoEntityHelper;

@Configuration
public class TokenVerifyInterceptor {

	@Bean
	public Advisor verifyTokenPoint() throws Exception {
		return InnerUtils.cutExpression(invocation -> {
			InnerUser oriUser = InnerUtils.getUser();
			try {
				HttpServletRequest request = InnerUtils.findArgs(invocation.getArguments(), HttpServletRequest.class);
				InnerUser tokenUser;
				/*-*/if (InnerUtils.getUser() != null || isExclude(invocation));// skip
				else if (null != (tokenUser = getTokenUser(request))) InnerUtils.setUser(tokenUser);// tokenUser
				else if (isPublicAction(invocation));// skip
				else throw ConstSettings.oauthFailError;// throw
				return invocation.proceed();
			} finally {
				InnerUtils.setUser(oriUser);
			}
		}, ConstSettings.OUTEST_CUT_POINT, ConstSettings.FIRST_ORDER + 1);
	}

	private static boolean isExclude(MethodInvocation invocation) throws Exception {
		String action = invocation.getMethod().getName();
		return "exists".equals(action);
	}

	private static boolean isPublicAction(MethodInvocation invocation) throws Exception {
		String action = invocation.getMethod().getName();
		if (!String.class.isInstance(invocation.getArguments()[0])) {
			return false;
		} else {
			String resourceName = (String) invocation.getArguments()[0];
			if (resourceName == null) {
				return false;
			} else {
				Set<String> actionSet = PoEntityHelper.getResourcePublicActionMap().get(resourceName);
				return (actionSet != null && actionSet.contains(action));
			}
		}
	}

	private static InnerUser getTokenUser(HttpServletRequest request) {
		InnerUser tokenUser = null;
		String token = InnerUtils.ifNull(request.getHeader("token"), () -> request.getParameter("token"));
		if (token != null) {
			GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
			try {
				tokenUser = srv.one(InnerUser.class, JwtUtils.decodeUserIdentify(token));
				if (tokenUser != null) JwtUtils.verifyToken(tokenUser, token);
			} catch (Throwable e) {
				tokenUser = null;
			}
		}
		return tokenUser;
	}
}
